package io.github.iogogogo.commons.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * Created by tao.zeng on 2024/12/22.
 * <p>
 * 性能追踪，时间打印
 */
@Data
@Slf4j
public class PerfTracker {

    private final static long DEFAULT_WARN_LOG_THRESHOLD = 500;

    private long startTime;

    private String methodName;

    private long threshold;

    private PerfTracker(String methodName) {
        this.startTime = DateTimeUtils.now();
        this.methodName = methodName;
        this.threshold = DEFAULT_WARN_LOG_THRESHOLD;
    }

    private PerfTracker(String methodName, long threshold) {
        this.startTime = DateTimeUtils.now();
        this.methodName = methodName;
        this.threshold = threshold;
    }

    public static TimerContext start() {
        StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
        return new TimerContext(String.join("#", stackTraceElement.getClassName(), stackTraceElement.getMethodName()));
    }

    public static TimerContext start(long threshold) {
        StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
        return new TimerContext(String.join("#", stackTraceElement.getClassName(), stackTraceElement.getMethodName()), threshold);
    }

    public static class TimerContext implements AutoCloseable {

        private final PerfTracker tracker;

        public TimerContext(String methodName) {
            this.tracker = new PerfTracker(methodName);
        }

        public TimerContext(String methodName, long threshold) {
            this.tracker = new PerfTracker(methodName, threshold);
        }

        /**
         * 关闭资源并根据执行时间记录警告日志
         * <p>
         * 当执行时间超过特定阈值时，此方法会记录一个警告日志，以帮助开发者识别和分析可能的性能瓶颈
         */
        @Override
        public void close() {
            // 计算当前时间与开始执行时间的差值，得到执行时间
            long executeTime = DateTimeUtils.now() - tracker.getStartTime();

            // 判断是否设置了自定义阈值，以决定使用自定义阈值还是默认阈值
            boolean sign = tracker.getThreshold() != DEFAULT_WARN_LOG_THRESHOLD;

            // 根据是否设置自定义阈值和执行时间，判断是否需要显示执行时间
            boolean showTime = sign ? executeTime > tracker.getThreshold() : executeTime > DEFAULT_WARN_LOG_THRESHOLD;

            // 根据是否设置自定义阈值，选择相应的阈值
            long threshold = sign ? tracker.getThreshold() : DEFAULT_WARN_LOG_THRESHOLD;

            // 如果执行时间超过阈值，则记录警告日志，包含方法名、阈值和执行时间
            if (showTime)
                log.warn("method: {}, threshold: {} ms, executeTime: {} ms", tracker.getMethodName(), threshold, executeTime);
        }
    }
}
